/*
	Programação Concorrente
	Trabalho 1
	Turma A

	Adilson Rapozo
	Luiz Bertoni
	Rodrigo Costa
*/

#include "../util/util.h"
#include <math.h>
#include <string.h>
#include <time.h>
#include <pthread.h>

typedef struct strut{
	mpf_t x;
	mpf_t xi;
	mpf_t xr;
	mpf_t y;
	mpf_t yi;
	mpf_t z;
	mpf_t aux;
} strut;

strut borwein;

pthread_mutex_t mut1 = PTHREAD_MUTEX_INITIALIZER;
pthread_mutex_t mut2 = PTHREAD_MUTEX_INITIALIZER;
pthread_mutex_t mut3 = PTHREAD_MUTEX_INITIALIZER;

void parcelax ( strut *borwein){

	pthread_mutex_lock(&mut1);

	mpf_ui_div(borwein->xi,1,borwein->xr);
        mpf_add(borwein->xi,borwein->xr,borwein->xi);
        mpf_div_ui(borwein->xi,borwein->xi,2);

        pthread_mutex_unlock(&mut1);
}


void parcelay ( strut *borwein){

	pthread_mutex_lock(&mut2);

	mpf_add_ui(borwein->yi,borwein->y,1);
        mpf_mul(borwein->yi,borwein->xr,borwein->yi);
        mpf_add(borwein->aux,borwein->x,borwein->y);
        mpf_div(borwein->yi,borwein->yi,borwein->aux);
        pthread_mutex_unlock(&mut2);
}

void parcelaz ( strut *borwein){

        pthread_mutex_lock(&mut3);

        mpf_add_ui(borwein->aux,borwein->xi,1);
        mpf_mul(borwein->aux,borwein->z,borwein->aux);
        mpf_mul(borwein->aux,borwein->aux,borwein->yi);
        mpf_add_ui(borwein->z,borwein->yi,1);
        mpf_div(borwein->z,borwein->aux,borwein->z);

        pthread_mutex_unlock(&mut3);
}


int main (void){


	pthread_t t1,t2,t3;
        int iteracao;
        clock_t start,end;
    	FILE *fp,*fp2;
        float desempenho;

        /*definindo a precisão a ser utilizada*/
        mpf_set_default_prec(PRECISION_FOR_10M);

        mpf_init(borwein.xr);
        mpf_init(borwein.x);
        mpf_init(borwein.xi);
        mpf_init(borwein.y);
        mpf_init(borwein.yi);
        mpf_init(borwein.z);
        mpf_init(borwein.aux);
        mpf_sqrt_ui(borwein.xi,2);
        mpf_add_ui(borwein.z,borwein.xi,2);

        start = clock();
        fp2 = fopen(REAL_PI,"r");

        for(iteracao=0; iteracao <= 24; iteracao++){

                mpf_set(borwein.x,borwein.xi);
                mpf_set(borwein.y,borwein.yi);
                mpf_sqrt(borwein.xr,borwein.x);

                pthread_create(&t1, NULL, (void*)parcelax,&borwein);
                pthread_create(&t2, NULL, (void*)parcelay,&borwein);

                pthread_join(t1,NULL);
                pthread_join(t2,NULL);


                pthread_create(&t3, NULL, (void*)parcelaz,&borwein);
                pthread_join(t3,NULL);


                /*salva arquivo*/
                savePI(&fp,"b_par",borwein.z, (unsigned long)iteracao);

                /*Imprime quantidade de digitos corretos*/
                printf("Obtained %lu correct digits in iteration #%d.\n",compare(fp,fp2),iteracao);

                fclose(fp);

        }
        fclose(fp2);
        end = clock();

        desempenho = ((double)(end-start)/CLOCKS_PER_SEC);

        printf("Concurrent Borwein: %.10f seconds.\n",desempenho);

        mpf_clear(borwein.xr);
        mpf_clear(borwein.x);
        mpf_clear(borwein.xi);
        mpf_clear(borwein.y);
        mpf_clear(borwein.yi);
        mpf_clear(borwein.z);
        mpf_clear(borwein.aux);

        pthread_mutex_destroy(&mut1);
        pthread_mutex_destroy(&mut2);
        pthread_mutex_destroy(&mut3);

        pthread_exit(NULL);

        return 0;

}
